package live.testdemo.bazi.service.impl;

import com.nlf.calendar.EightChar;
import com.nlf.calendar.Lunar;
import com.nlf.calendar.util.LunarUtil;

import org.springframework.stereotype.Service;

import java.util.List;

import live.testdemo.bazi.common.constants.DiZhi;
import live.testdemo.bazi.common.constants.TianGan;
import live.testdemo.bazi.common.constants.WuXing;
import live.testdemo.bazi.common.domain.DayunLiunian;
import live.testdemo.bazi.dao.entry.EightCharWangDu;
import live.testdemo.bazi.service.BaziService;
import live.testdemo.bazi.service.Geju;
import live.testdemo.bazi.service.MukuInfo;
import live.testdemo.bazi.service.Xiyong;
import live.testdemo.bazi.service.ZhiShi;
import lombok.extern.slf4j.Slf4j;

/**
 * @author LucasZhou
 * @description TODO
 * @date 2021/5/29 20:24
 */
@Slf4j
@Service
public class BaziServiceImpl implements BaziService {
    @Override
    public DayunLiunian getDayunLiunian(Lunar lunar) {
        return null;
    }

    @Override
    public boolean deling(Lunar lunar) {
        EightChar bazi = lunar.getEightChar();
        String monthDiShi = bazi.getMonthDiShi();
        //地势的字 只有一个时，就认为是不得势 两个字时 认为是得势
        return monthDiShi.length() > 1;
    }

    @Override
    public boolean dedi(Lunar lunar) {
        EightChar bazi = lunar.getEightChar();
        String dayDiShi = bazi.getDayDiShi();
        //地势的字 只有一个时，就认为是不得势 两个字时 认为是得势
        return dayDiShi.length() > 1;
    }

    @Override
    public boolean deshi(Lunar lunar) {
        return false;
    }

    @Override
    public boolean deqi(Lunar lunar) {
        return false;
    }

    @Override
    public Geju dingGeju(Lunar lunar) {
        return null;
    }

    @Override
    public List<String> getKongwang(Lunar lunar) {
        return null;
    }

    @Override
    public MukuInfo getMukuInfo(Lunar lunar) {
        return null;
    }

    @Override
    public boolean wangshuai(Lunar lunar) {
        return false;
    }

    @Override
    public Xiyong getXiyongShen(Lunar lunar) {
        return null;
    }

    @Override
    public ZhiShi getZhishi(Lunar lunar) {
        return null;
    }

    @Override
    public EightCharWangDu getWangDu(Lunar lunar) {
        //目前计算的是 静态旺度
        EightCharWangDu eightCharWangDu = new EightCharWangDu();
        //处理静态旺度
        dealStasticWangDu(lunar, eightCharWangDu);
        //处理通根旺度
        dealTongGenWangDU(lunar, eightCharWangDu);
        //处理月令秉气理论
        dealYueLingBingQi(lunar, eightCharWangDu);
        return eightCharWangDu;
    }

    /**
     * 处理月令禀气理论
     *
     * @param lunar
     * @param eightCharWangDu
     */
    private void dealYueLingBingQi(Lunar lunar, EightCharWangDu eightCharWangDu) {

    }

    /**
     * 处理通根旺度
     *
     * @param lunar
     * @param eightCharWangDu
     */
    private void dealTongGenWangDU(Lunar lunar, EightCharWangDu eightCharWangDu) {
        dealYearTongGen(lunar, eightCharWangDu);
        dealMonthTongGen(lunar, eightCharWangDu);
        dealDayTongGen(lunar, eightCharWangDu);
        dealTimeTongGen(lunar, eightCharWangDu);
    }

    /**
     * 处理时柱通根
     *
     * @param lunar
     * @param eightCharWangDu
     */
    private void dealTimeTongGen(Lunar lunar, EightCharWangDu eightCharWangDu) {
        //四柱年柱初始位置1 月柱为2 日柱位3 时柱为4
        EightChar eightChar = lunar.getEightChar();
        TianGan tianGan = TianGan.valueOf(eightChar.getTimeGan());
        if (tianGan.isTongGen(eightChar.getYearZhi())) {
            tongGenJiSuan(4, 1, tianGan, eightChar, eightCharWangDu);
        }
        if (tianGan.isTongGen(eightChar.getMonthZhi())) {
            tongGenJiSuan(4, 2, tianGan, eightChar, eightCharWangDu);
        }
        if (tianGan.isTongGen(eightChar.getDayZhi())) {
            tongGenJiSuan(4, 3, tianGan, eightChar, eightCharWangDu);
        }
        if (tianGan.isTongGen(eightChar.getTimeZhi())) {
            tongGenJiSuan(4, 4, tianGan, eightChar, eightCharWangDu);
        }
    }

    /**
     * 处理日柱通根
     *
     * @param lunar
     * @param eightCharWangDu
     */
    private void dealDayTongGen(Lunar lunar, EightCharWangDu eightCharWangDu) {
        //四柱年柱初始位置1 月柱为2 日柱位3 时柱为4
        EightChar eightChar = lunar.getEightChar();
        TianGan tianGan = TianGan.valueOf(eightChar.getDayGan());
        if (tianGan.isTongGen(eightChar.getYearZhi())) {
            tongGenJiSuan(3, 1, tianGan, eightChar, eightCharWangDu);
        }
        if (tianGan.isTongGen(eightChar.getMonthZhi())) {
            tongGenJiSuan(3, 2, tianGan, eightChar, eightCharWangDu);
        }
        if (tianGan.isTongGen(eightChar.getDayZhi())) {
            tongGenJiSuan(3, 3, tianGan, eightChar, eightCharWangDu);
        }
        if (tianGan.isTongGen(eightChar.getTimeZhi())) {
            tongGenJiSuan(3, 4, tianGan, eightChar, eightCharWangDu);
        }
    }

    /**
     * 处理月柱通根
     *
     * @param lunar
     * @param eightCharWangDu
     */
    private void dealMonthTongGen(Lunar lunar, EightCharWangDu eightCharWangDu) {
        //四柱年柱初始位置1 月柱为2 日柱位3 时柱为4
        EightChar eightChar = lunar.getEightChar();
        TianGan tianGan = TianGan.valueOf(eightChar.getMonthGan());
        if (tianGan.isTongGen(eightChar.getYearZhi())) {
            tongGenJiSuan(2, 1, tianGan, eightChar, eightCharWangDu);
        }
        if (tianGan.isTongGen(eightChar.getMonthZhi())) {
            tongGenJiSuan(2, 2, tianGan, eightChar, eightCharWangDu);
        }
        if (tianGan.isTongGen(eightChar.getDayZhi())) {
            tongGenJiSuan(2, 3, tianGan, eightChar, eightCharWangDu);
        }
        if (tianGan.isTongGen(eightChar.getTimeZhi())) {
            tongGenJiSuan(2, 4, tianGan, eightChar, eightCharWangDu);
        }
    }

    /**
     * 处理年柱通根
     *
     * @param lunar
     * @param eightCharWangDu
     */
    private void dealYearTongGen(Lunar lunar, EightCharWangDu eightCharWangDu) {
        //四柱年柱初始位置1 月柱为2 日柱位3 时柱为4
        EightChar eightChar = lunar.getEightChar();
        TianGan tianGan = TianGan.valueOf(eightChar.getYearGan());
        if (tianGan.isTongGen(eightChar.getYearZhi())) {
            tongGenJiSuan(1, 1, tianGan, eightChar, eightCharWangDu);
        }
        if (tianGan.isTongGen(eightChar.getMonthZhi())) {
            tongGenJiSuan(1, 2, tianGan, eightChar, eightCharWangDu);
        }
        if (tianGan.isTongGen(eightChar.getDayZhi())) {
            tongGenJiSuan(1, 3, tianGan, eightChar, eightCharWangDu);
        }
        if (tianGan.isTongGen(eightChar.getTimeZhi())) {
            tongGenJiSuan(1, 4, tianGan, eightChar, eightCharWangDu);
        }
    }

    /**
     * 干支旺度计算
     *
     * @param gan
     * @param zhi
     * @param tianGan
     * @param eightChar
     * @param eightCharWangDu
     */
    private void tongGenJiSuan(int gan, int zhi, TianGan tianGan, EightChar eightChar, EightCharWangDu eightCharWangDu) {
        if (gan == zhi) {
            String diZhi = switch (zhi) {
                case 1 -> eightChar.getYearZhi();
                case 2 -> eightChar.getMonthZhi();
                case 3 -> eightChar.getDayZhi();
                case 4 -> eightChar.getTimeZhi();
                default -> throw new IllegalStateException("Unexpected value: " + zhi);
            };
            if (tianGan.isTongGen(diZhi)) {
                return;
            }
        }
        //判断干在支左侧还是右侧，方便进行加减
        boolean flag = gan < zhi;
        //看天干是否能"移位" 天干每移一次位 加1 或减一 初始值gan小于zhi时，gan加一
        //看地支是否能"移位" 地支每移一次位 减1 或加一 初始值gan大于zhi时，zhi加一
        int finalGan = gan;
        for (int i = 0; i < 4 - Math.abs(finalGan); i++) {
            if (tianGan.isTongWuXing(getTianGanByIndex(flag ? gan + 1 : gan - 1, eightChar))) {
                gan = flag ? ++gan : --gan;
            } else {
                break;
            }
        }
        int finalZhi = zhi;
        for (int i = 0; i < 4 - Math.abs(finalZhi); i++) {
            if (tianGan.isTongGen(getDiZhiByIndex(flag ? zhi - 1 : zhi + 1, eightChar))) {
                zhi = flag ? --zhi : ++zhi;
            } else {
                break;
            }
        }

        if (gan < zhi ^ flag || gan == zhi) {
            //如果干支位置恰好相等 表明此时处于同柱通根状态
            //如果干支已经跨越，说明已经出现了同柱通根现象，按最近通根计算。
        } else {
            //如果干小于支，表明并没有出现同柱通根现象
            switch (Math.abs(gan - zhi)) {
                case 1 -> {
                    //相差一柱 相邻通根
                    if (zhi == 2) {
                        //如果是月柱通根，依然按同柱通根计算
                    } else {
                        //如果不是月柱通根，按临柱通根计算
                        addTianGanWangDu(eightCharWangDu, tianGan.name(), -0.5);
                    }
                }
                case 2 -> {
                    //相差两柱 相邻通根
                    if (zhi == 2) {
                        //如果是月柱通根，依然按同柱通根计算
                    } else {
                        //如果不是月柱通根，按隔柱通根计算
                        addTianGanWangDu(eightCharWangDu, tianGan.name(), -1);
                    }
                }
                case 3 -> {
                    //相差两柱 相邻通根
                    if (zhi == 2) {
                        //如果是月柱通根，依然按同柱通根计算
                    } else {
                        //如果不是月柱通根，按遥隔通根计算
                        addTianGanWangDu(eightCharWangDu, tianGan.name(), -2);
                    }
                }
            }
        }
    }

    private String getTianGanByIndex(int gan, EightChar eightChar) {
        String ganStr = switch (gan) {
            case 1 -> eightChar.getYearGan();
            case 2 -> eightChar.getMonthGan();
            case 3 -> eightChar.getDayGan();
            case 4 -> eightChar.getTimeGan();
            default -> throw new IllegalStateException("Unexpected value: " + gan);
        };
        return ganStr;
    }

    private String getDiZhiByIndex(int diZhi, EightChar eightChar) {
        String ganStr = switch (diZhi) {
            case 1 -> eightChar.getYearZhi();
            case 2 -> eightChar.getMonthZhi();
            case 3 -> eightChar.getDayZhi();
            case 4 -> eightChar.getTimeZhi();
            default -> throw new IllegalStateException("Unexpected value: " + diZhi);
        };
        return ganStr;
    }

    /**
     * 获取静态旺度
     *
     * @param lunar
     * @param eightCharWangDu
     */
    private void dealStasticWangDu(Lunar lunar, EightCharWangDu eightCharWangDu) {
        EightChar eightChar = lunar.getEightChar();
        //处理天干
        addTianGanWangDu(eightCharWangDu, eightChar.getYearGan(), 1);
        addTianGanWangDu(eightCharWangDu, eightChar.getMonthGan(), 1);
        addTianGanWangDu(eightCharWangDu, eightChar.getDayGan(), 1);
        addTianGanWangDu(eightCharWangDu, eightChar.getTimeGan(), 1);
        //处理地支旺度
        addDiZhiWangDu(eightCharWangDu, eightChar, eightChar.getYearZhi());
        addDiZhiWangDu(eightCharWangDu, eightChar, eightChar.getMonthZhi());
        addDiZhiWangDu(eightCharWangDu, eightChar, eightChar.getDayZhi());
        addDiZhiWangDu(eightCharWangDu, eightChar, eightChar.getTimeZhi());
    }

    private void addDiZhiWangDu(EightCharWangDu eightCharWangDu, EightChar eightChar, String zhi) {
        //四柱干支五行
        String yearWuXing = eightChar.getYearWuXing();
        String monthWuXing = eightChar.getMonthWuXing();
        String dayWuXing = eightChar.getDayWuXing();
        String timeWuXing = eightChar.getTimeWuXing();
        List<String> yearHideGan = LunarUtil.ZHI_HIDE_GAN.get(zhi);
        switch (DiZhi.valueOf(zhi)) {
            case 辰 -> {
                switch (DiZhi.valueOf(eightChar.getMonthZhi())) {
                    //生于亥子月
                    case 亥, 子 -> {
                        //丑土党重，三个或三个以上并且连成一片时
                        if (WuXing.valueOf(monthWuXing.substring(1, 2)).equals(WuXing.土) &&
                                WuXing.valueOf(dayWuXing.substring(1, 2)).equals(WuXing.土) &&
                                (WuXing.valueOf(yearWuXing.substring(1, 2)).equals(WuXing.土)) || WuXing.valueOf(timeWuXing.substring(1, 2)).equals(WuXing.土)) {
                            addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 2);
                            addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 2);
                            addTianGanWangDu(eightCharWangDu, yearHideGan.get(2), 2);
                        } else {
                            addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 0);
                            addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 2);
                            addTianGanWangDu(eightCharWangDu, yearHideGan.get(2), 3);
                        }
                    }
                    //生于丑月
                    case 丑 -> {
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 2);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 2);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(2), 2);
                    }
                    //生于申酉月
                    case 申, 酉 -> {
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 2);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 2);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(2), 2);
                    }
                    //生于其他月
                    default -> {
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 3);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 2);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(2), 1);
                    }
                }
            }
            case 丑 -> {
                switch (DiZhi.valueOf(eightChar.getMonthZhi())) {
                    //生于亥子月
                    case 亥, 子 -> {
                        //丑土党重，三个或三个以上并且连成一片时
                        if (WuXing.valueOf(monthWuXing.substring(1, 2)).equals(WuXing.土) &&
                                WuXing.valueOf(dayWuXing.substring(1, 2)).equals(WuXing.土) &&
                                (WuXing.valueOf(yearWuXing.substring(1, 2)).equals(WuXing.土)) || WuXing.valueOf(timeWuXing.substring(1, 2)).equals(WuXing.土)) {
                            addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 1);
                            addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 2);
                            addTianGanWangDu(eightCharWangDu, yearHideGan.get(2), 2);
                        } else {
                            addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 0);
                            addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 3);
                            addTianGanWangDu(eightCharWangDu, yearHideGan.get(2), 2);
                        }
                    }
                    //生于丑月
                    case 丑 -> {
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 3);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 2);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(2), 2);
                    }
                    //生于申酉月
                    case 申, 酉 -> {
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 2);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 2);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(2), 2);
                    }
                    //生于其他月
                    default -> {
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 3);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 1);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(2), 2);
                    }
                }
            }
            case 未 -> {
                //todo 脆金之力减半 待实现
                switch (DiZhi.valueOf(eightChar.getMonthZhi())) {
                    //生于巳午未月
                    case 巳, 午, 未 -> {
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 2);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 4);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(2), 0);
                    }
                    //生于申酉月
                    case 申, 酉 -> {
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 3);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 2);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(2), 1);
                    }
                    //生于戌月
                    case 戌 -> {
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 3);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 3);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(2), 0);
                    }
                    //生于亥子丑月
                    case 亥, 子, 丑 -> {
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 2);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 2);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(2), 3);
                    }
                    //生于辰月
                    case 辰 -> {
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 3);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 1);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(2), 2);
                    }
                    //生于其他月
                    default -> {
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 3);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 2);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(2), 1);
                    }
                }
            }
            case 戌 -> {
                //todo 脆金之力减半 待实现
                switch (DiZhi.valueOf(eightChar.getMonthZhi())) {
                    //生于巳午未月
                    case 巳, 午, 未 -> {
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 2);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 0);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(2), 4);
                    }
                    //生于申酉月
                    case 申, 酉 -> {
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 2);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 2);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(2), 2);
                    }
                    //生于戌月
                    case 戌 -> {
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 3);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 0);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(2), 3);
                    }
                    //生于亥子丑月
                    case 亥, 子, 丑 -> {
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 2);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 2);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(2), 3);
                    }
                    //生于辰月
                    case 辰 -> {
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 3);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 2);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(2), 1);
                    }
                    //生于其他月
                    default -> {
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 3);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 1);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(2), 2);
                    }
                }
            }
            default -> {
                //处理常规地支
                switch (yearHideGan.size()) {
                    //纯本气
                    case 1 -> addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 5);
                    //半本气
                    case 2 -> {
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 4);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 2);
                    }
                    //本气
                    case 3 -> {
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(0), 3);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 2);
                        addTianGanWangDu(eightCharWangDu, yearHideGan.get(1), 1);
                    }
                }
            }
        }
    }

    /**
     * 计算五行旺度
     *
     * @param eightCharWangDu
     * @param gan
     * @param wangDu
     */
    private void addTianGanWangDu(EightCharWangDu eightCharWangDu, String gan, double wangDu) {
        switch (WuXing.valueOf(LunarUtil.WU_XING_GAN.get(gan))) {
            case 木 -> eightCharWangDu.getMu().setWangDuValue(eightCharWangDu.getMu().getWangDuValue() + wangDu);
            case 火 -> eightCharWangDu.getHuo().setWangDuValue(eightCharWangDu.getHuo().getWangDuValue() + wangDu);
            case 土 -> eightCharWangDu.getTu().setWangDuValue(eightCharWangDu.getTu().getWangDuValue() + wangDu);
            case 金 -> eightCharWangDu.getJin().setWangDuValue(eightCharWangDu.getJin().getWangDuValue() + wangDu);
            case 水 -> eightCharWangDu.getShui().setWangDuValue(eightCharWangDu.getShui().getWangDuValue() + wangDu);
        }
    }
}
